#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
UI主界面模块
负责主界面与弹窗UI设计
"""

import sys
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                             QTableWidget, QTableWidgetItem, QPushButton, QLabel, QSystemTrayIcon,
                             QMenu, QAction, QMessageBox, QGroupBox, QFormLayout, QLineEdit,
                             QSpinBox, QFileDialog, QTextEdit, QHeaderView, QDialog)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QIcon, QColor
from logger import Logger
from process_monitor import ProcessMonitor


class ProcessDialog(QDialog):
    """进程添加/编辑对话框"""

    def __init__(self, process_data=None, parent=None):
        """
        初始化对话框
        
        Args:
            process_data (dict): 进程数据(编辑模式时提供)
            parent (QWidget): 父窗口
        """
        super().__init__(parent)
        self.process_data = process_data
        self.init_ui()

    def init_ui(self):
        """初始化UI"""
        self.setWindowTitle("添加进程" if self.process_data is None else "编辑进程")
        self.setFixedSize(500, 400)

        layout = QVBoxLayout()

        # 创建表单
        form_group = QGroupBox("进程配置")
        form_layout = QFormLayout()

        # 进程名称
        self.name_edit = QLineEdit()
        self.name_edit.setPlaceholderText("例如: notepad.exe")
        form_layout.addRow(QLabel("进程名称(*):"), self.name_edit)

        # 启动程序路径
        path_layout = QHBoxLayout()
        self.executable_edit = QLineEdit()
        self.executable_edit.setPlaceholderText("点击浏览选择.exe文件")
        browse_btn = QPushButton("浏览")
        browse_btn.clicked.connect(self.browse_executable)
        path_layout.addWidget(self.executable_edit)
        path_layout.addWidget(browse_btn)
        form_layout.addRow(QLabel("启动程序路径(*):"), path_layout)

        # 启动参数
        self.args_edit = QLineEdit()
        self.args_edit.setPlaceholderText("可选，例如: D:\\test.txt")
        form_layout.addRow(QLabel("启动参数:"), self.args_edit)

        # 工作目录
        workdir_layout = QHBoxLayout()
        self.workdir_edit = QLineEdit()
        self.workdir_edit.setPlaceholderText("可选，默认使用程序所在目录")
        browse_workdir_btn = QPushButton("浏览")
        browse_workdir_btn.clicked.connect(self.browse_workdir)
        workdir_layout.addWidget(self.workdir_edit)
        workdir_layout.addWidget(browse_workdir_btn)
        form_layout.addRow(QLabel("工作目录:"), workdir_layout)

        # 检测间隔
        self.interval_spin = QSpinBox()
        self.interval_spin.setRange(1, 300)
        self.interval_spin.setValue(5)
        form_layout.addRow(QLabel("检测间隔(秒):"), self.interval_spin)

        # 重启重试次数
        self.retries_spin = QSpinBox()
        self.retries_spin.setRange(1, 10)
        self.retries_spin.setValue(3)
        form_layout.addRow(QLabel("重启重试次数:"), self.retries_spin)

        # 重启间隔
        self.retry_interval_spin = QSpinBox()
        self.retry_interval_spin.setRange(1, 60)
        self.retry_interval_spin.setValue(10)
        form_layout.addRow(QLabel("重启间隔(秒):"), self.retry_interval_spin)

        form_group.setLayout(form_layout)
        layout.addWidget(form_group)

        # 按钮
        btn_layout = QHBoxLayout()
        ok_btn = QPushButton("确定")
        cancel_btn = QPushButton("取消")
        ok_btn.clicked.connect(self.accept)
        cancel_btn.clicked.connect(self.reject)
        btn_layout.addStretch()
        btn_layout.addWidget(ok_btn)
        btn_layout.addWidget(cancel_btn)
        layout.addLayout(btn_layout)

        self.setLayout(layout)

        # 如果是编辑模式，填充数据
        if self.process_data:
            self.name_edit.setText(self.process_data.get("name", ""))
            self.executable_edit.setText(self.process_data.get("executable", ""))
            self.args_edit.setText(self.process_data.get("args", ""))
            self.workdir_edit.setText(self.process_data.get("work_dir", ""))
            self.interval_spin.setValue(self.process_data.get("check_interval", 5))
            self.retries_spin.setValue(self.process_data.get("max_retries", 3))
            self.retry_interval_spin.setValue(self.process_data.get("retry_interval", 10))

    def browse_executable(self):
        """浏览选择可执行文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择可执行文件", "", "Executable Files (*.exe)"
        )
        if file_path:
            self.executable_edit.setText(file_path)

    def browse_workdir(self):
        """浏览选择工作目录"""
        dir_path = QFileDialog.getExistingDirectory(self, "选择工作目录")
        if dir_path:
            self.workdir_edit.setText(dir_path)

    def accept(self):
        """确认操作"""
        # 简单验证
        if not self.name_edit.text().strip():
            QMessageBox.warning(self, "输入错误", "进程名称不能为空")
            return

        if not self.executable_edit.text().strip():
            QMessageBox.warning(self, "输入错误", "启动程序路径不能为空")
            return

        if not self.executable_edit.text().endswith('.exe'):
            QMessageBox.warning(self, "输入错误", "启动程序必须是.exe文件")
            return

        if not os.path.exists(self.executable_edit.text()):
            QMessageBox.warning(self, "输入错误", "启动程序文件不存在")
            return

        self.process_data = {
            "name": self.name_edit.text().strip(),
            "executable": self.executable_edit.text().strip(),
            "args": self.args_edit.text().strip(),
            "work_dir": self.workdir_edit.text().strip() if self.workdir_edit.text().strip() else None,
            "check_interval": self.interval_spin.value(),
            "max_retries": self.retries_spin.value(),
            "retry_interval": self.retry_interval_spin.value()
        }
        super().accept()

    def get_process_data(self):
        """
        获取进程数据
        
        Returns:
            dict: 进程配置数据
        """
        return self.process_data


class MainWindow(QMainWindow):
    """主窗口类"""

    def __init__(self, config_manager):
        """
        初始化主窗口
        
        Args:
            config_manager: 配置管理器实例
        """
        super().__init__()
        self.config_manager = config_manager
        self.logger = Logger(self.config_manager.log_dir)
        self.monitor = ProcessMonitor(self.logger)
        self.init_ui()
        self.init_tray_icon()
        self.load_processes()
        self.start_monitoring()

    def init_ui(self):
        """初始化UI"""
        self.setWindowTitle("进程守护看门狗")
        self.setGeometry(100, 100, 1000, 700)

        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        # 进程列表区域
        process_group = QGroupBox("进程列表")
        process_layout = QVBoxLayout()

        self.process_table = QTableWidget()
        self.process_table.setColumnCount(5)
        self.process_table.setHorizontalHeaderLabels([
            "进程名称", "当前状态", "检测间隔", "上次启动时间", "启动路径"
        ])
        
        # 设置表格属性
        self.process_table.setSelectionBehavior(QTableWidget.SelectRows)
        self.process_table.setSelectionMode(QTableWidget.SingleSelection)
        self.process_table.setEditTriggers(QTableWidget.NoEditTriggers)
        self.process_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
        self.process_table.itemSelectionChanged.connect(self.on_selection_changed)
        
        process_layout.addWidget(self.process_table)
        process_group.setLayout(process_layout)
        main_layout.addWidget(process_group)

        # 操作按钮区域
        button_layout = QHBoxLayout()
        
        self.add_btn = QPushButton("添加进程")
        self.edit_btn = QPushButton("编辑进程")
        self.delete_btn = QPushButton("删除进程")
        self.start_btn = QPushButton("手动启动")
        self.stop_btn = QPushButton("手动停止")
        self.refresh_btn = QPushButton("刷新状态")
        
        # 连接按钮信号
        self.add_btn.clicked.connect(self.add_process)
        self.edit_btn.clicked.connect(self.edit_process)
        self.delete_btn.clicked.connect(self.delete_process)
        self.start_btn.clicked.connect(self.start_process)
        self.stop_btn.clicked.connect(self.stop_process)
        self.refresh_btn.clicked.connect(self.refresh_status)
        
        # 初始禁用部分按钮
        self.update_button_states()
        
        button_layout.addWidget(self.add_btn)
        button_layout.addWidget(self.edit_btn)
        button_layout.addWidget(self.delete_btn)
        button_layout.addWidget(self.start_btn)
        button_layout.addWidget(self.stop_btn)
        button_layout.addWidget(self.refresh_btn)
        button_layout.addStretch()
        
        main_layout.addLayout(button_layout)

        # 日志显示区域
        log_group = QGroupBox("运行日志")
        log_layout = QVBoxLayout()
        
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        log_layout.addWidget(self.log_text)
        
        # 日志操作按钮
        log_btn_layout = QHBoxLayout()
        clear_log_btn = QPushButton("清空日志")
        export_log_btn = QPushButton("导出日志")
        clear_log_btn.clicked.connect(self.clear_logs)
        export_log_btn.clicked.connect(self.export_logs)
        log_btn_layout.addStretch()
        log_btn_layout.addWidget(clear_log_btn)
        log_btn_layout.addWidget(export_log_btn)
        log_layout.addLayout(log_btn_layout)
        
        log_group.setLayout(log_layout)
        main_layout.addWidget(log_group)
        
        # 定时刷新日志和状态
        self.timer = QTimer()
        self.timer.timeout.connect(self.refresh_status)
        self.timer.start(1000)  # 每秒刷新一次

    def init_tray_icon(self):
        """初始化系统托盘图标"""
        if not QSystemTrayIcon.isSystemTrayAvailable():
            return
            
        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon("icon.ico"))  # 需要提供图标文件
        
        # 创建托盘菜单
        tray_menu = QMenu()
        show_action = QAction("显示主窗口", self)
        quit_action = QAction("退出软件", self)
        show_action.triggered.connect(self.show)
        quit_action.triggered.connect(QApplication.quit)
        tray_menu.addAction(show_action)
        tray_menu.addAction(quit_action)
        
        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.show()

    def load_processes(self):
        """加载进程配置"""
        processes = self.config_manager.get_processes()
        for process in processes:
            self.monitor.add_process(process)
        self.refresh_status()

    def start_monitoring(self):
        """启动监控"""
        self.monitor.start_monitoring()

    def refresh_status(self):
        """刷新状态显示"""
        self.process_table.setRowCount(len(self.monitor.processes))
        
        for i, process_info in enumerate(self.monitor.processes):
            config = process_info["config"]
            
            # 进程名称
            name_item = QTableWidgetItem(config["name"])
            self.process_table.setItem(i, 0, name_item)
            
            # 当前状态
            status_item = QTableWidgetItem(process_info["status"])
            if process_info["status"] == "运行中":
                status_item.setForeground(QColor(0, 128, 0))  # 绿色
            elif process_info["status"] == "已停止":
                status_item.setForeground(QColor(255, 0, 0))  # 红色
            elif process_info["status"] == "异常":
                status_item.setForeground(QColor(255, 165, 0))  # 橙色
            self.process_table.setItem(i, 1, status_item)
            
            # 检测间隔
            interval_item = QTableWidgetItem(str(config.get("check_interval", 5)))
            self.process_table.setItem(i, 2, interval_item)
            
            # 上次启动时间
            last_start_item = QTableWidgetItem(process_info["last_start_time"] or "从未启动")
            self.process_table.setItem(i, 3, last_start_item)
            
            # 启动路径
            path_item = QTableWidgetItem(config["executable"])
            path_item.setToolTip(config["executable"])
            self.process_table.setItem(i, 4, path_item)
            
        # 刷新日志显示
        self.refresh_logs()

    def refresh_logs(self):
        """刷新日志显示"""
        logs = self.logger.get_recent_logs(50)  # 显示最近50行日志
        self.log_text.clear()
        for log in logs:
            self.log_text.append(log.strip())

    def on_selection_changed(self):
        """选择改变时更新按钮状态"""
        self.update_button_states()

    def update_button_states(self):
        """更新按钮状态"""
        has_selection = bool(self.process_table.selectedItems())
        self.edit_btn.setEnabled(has_selection)
        self.delete_btn.setEnabled(has_selection)
        self.start_btn.setEnabled(has_selection)
        self.stop_btn.setEnabled(has_selection)

    def add_process(self):
        """添加进程"""
        dialog = ProcessDialog(parent=self)
        result = dialog.exec_()
        
        process_data = dialog.get_process_data()
        if process_data and result == QDialog.Accepted:
            self.config_manager.add_process(process_data)
            self.monitor.add_process(process_data)
            self.refresh_status()

    def edit_process(self):
        """编辑进程"""
        selected_rows = self.process_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "操作失败", "请先选择要编辑的进程")
            return
            
        row = selected_rows[0].row()
        process_info = self.monitor.get_process_status(row)
        if not process_info:
            return
            
        dialog = ProcessDialog(process_info["config"], parent=self)
        result = dialog.exec_()
        
        process_data = dialog.get_process_data()
        if process_data and result == QDialog.Accepted:
            self.config_manager.update_process(row, process_data)
            self.monitor.processes[row]["config"] = process_data
            self.refresh_status()

    def delete_process(self):
        """删除进程"""
        selected_rows = self.process_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "操作失败", "请先选择要删除的进程")
            return
            
        row = selected_rows[0].row()
        process_info = self.monitor.get_process_status(row)
        if not process_info:
            return
            
        reply = QMessageBox.question(
            self, 
            "确认删除", 
            f"确定要删除进程 {process_info['config']['name']} 吗？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            self.config_manager.remove_process(row)
            self.monitor.remove_process(row)
            self.refresh_status()

    def start_process(self):
        """手动启动进程"""
        selected_rows = self.process_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "操作失败", "请先选择要启动的进程")
            return
            
        row = selected_rows[0].row()
        success = self.monitor.start_process(row)
        if success:
            QMessageBox.information(self, "操作成功", "进程启动成功")
        else:
            QMessageBox.critical(self, "操作失败", "进程启动失败，请查看日志了解详情")
            
        self.refresh_status()

    def stop_process(self):
        """手动停止进程"""
        selected_rows = self.process_table.selectionModel().selectedRows()
        if not selected_rows:
            QMessageBox.warning(self, "操作失败", "请先选择要停止的进程")
            return
            
        row = selected_rows[0].row()
        success = self.monitor.stop_process(row)
        if success:
            QMessageBox.information(self, "操作成功", "进程停止成功")
        else:
            QMessageBox.critical(self, "操作失败", "进程停止失败，请查看日志了解详情")
            
        self.refresh_status()

    def clear_logs(self):
        """清空日志"""
        reply = QMessageBox.question(
            self,
            "确认清空",
            "确定要清空所有日志吗？",
            QMessageBox.Yes | QMessageBox.No
        )
        
        if reply == QMessageBox.Yes:
            # 清空当前日志文件
            try:
                with open(self.logger.log_file, 'w') as f:
                    f.write("")
                self.refresh_logs()
            except IOError as e:
                QMessageBox.critical(self, "操作失败", f"清空日志失败: {str(e)}")

    def export_logs(self):
        """导出日志"""
        file_path, _ = QFileDialog.getSaveFileName(
            self, "导出日志", "logs.txt", "Text Files (*.txt)"
        )
        
        if file_path:
            try:
                import shutil
                shutil.copy2(self.logger.log_file, file_path)
                QMessageBox.information(self, "导出成功", f"日志已导出到: {file_path}")
            except Exception as e:
                QMessageBox.critical(self, "导出失败", f"导出日志失败: {str(e)}")

    def closeEvent(self, event):
        """关闭事件处理"""
        if hasattr(self, 'tray_icon') and self.tray_icon.isVisible():
            QMessageBox.information(
                self, 
                "提示", 
                "程序将最小化到系统托盘，如需完全退出请使用托盘菜单"
            )
            self.hide()
            event.ignore()
        else:
            self.monitor.stop_monitoring()
            event.accept()